﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Glodon.Gdmp.DB;
using Glodon.Gdmp.UI;

namespace Glodon.Gdmp.SDK.Samples.InstanceUpdater
{
    /// <summary>
    /// 此示例演示实现IUpdater接口以进行图元的关联更新。
    /// </summary>
    public class InstanceUpdaterCmd : IExternalCommand
    {
        public Result Execute(UIDocument uiDocument)
        {
            try
            {
                var document = uiDocument.Document;
                string folderLocation = Assembly.GetExecutingAssembly().Location;

                #region 载入族。
                var familyName = "CustomWall";
                Family family = null;
                family = new ElementCollector(document).OfClass(typeof(Family)).FirstOrDefault(x => x as Family != null && (x as Family).Name.Equals(familyName)) as Family;
                if(null == family)
                {
                    var familyFile = Path.Combine($"{Path.GetDirectoryName(folderLocation)}", $"{familyName}.gac");
                    using (Transaction tran = new Transaction(document, "加载自定义墙族"))
                    {
                        tran.Start();
                        family = Family.Load(document, familyFile);
                        tran.Commit();
                    }
                }
                
                if(null == family)
                {
                    MessageBoard.Show($"异常为：未成功加载CustomWall.gac", "GDMPLab");
                    return Result.Failed;
                }
                #endregion

                #region 加载更新器。
                var customUpdater = new CustomUpdater();
                var isRegistered = UpdaterRegistry.IsUpdaterRegistered(customUpdater.GetUpdaterId(), document);
                if (!isRegistered)
                {
                    UpdaterRegistry.RegisterUpdater(customUpdater, document);
                }
                var filter = new UpdaterFilter();
                ElementChange change = ElementChange.Create(ElementChangeType.Added);
                UpdaterRegistry.AddTrigger(customUpdater.GetUpdaterId(), document, filter, change);
                #endregion

                #region 绘制灰色墙。
                var point = uiDocument.Selection.PickPoint();
                var instanceTypes = family.GetInstanceTypes();
                var greyWallType = instanceTypes.FirstOrDefault(x => x.Name.Equals("灰色墙"));

                var plane = Plane.CreateByOriginAndBasis(Vector3d.Zero, Vector3d.BasisX, Vector3d.BasisY);
                using (var tran = new Transaction(document, "创建灰色墙"))
                {
                    tran.Start();
                    var workPlane = WorkPlane.Create(document, plane, "工作平面");
                    FamilyInstance.Create(document, point, workPlane.Id, greyWallType.Id);
                    tran.Commit();
                }
                #endregion

                #region 移除更新器。
                isRegistered = UpdaterRegistry.IsUpdaterRegistered(customUpdater.GetUpdaterId(), document);
                if(isRegistered)
                {
                    UpdaterRegistry.UnregisterUpdater(customUpdater.GetUpdaterId(), document);
                }
                #endregion
                return Result.Succeeded;
            }
            catch(Exception ex)
            {
                // 可以通过Gdmp.Exceptions查看GDMP所定义的各类异常。
                if(!(ex is Gdmp.Exceptions.InvalidOperationException))
                {
                    string message = ex.Message;
                    MessageBoard.Show($"异常为：{message}", "GDMPLab");
                }
                return Result.Failed;
            }
        }
    }

    /// <summary>
    /// 实现自定义更新器。
    /// </summary>
    public class CustomUpdater : IUpdater
    {
        private UpdaterId m_id = UpdaterId.Create(new Guid("BB13AAD3-027F-4181-A558-A459FB1ADF62"));
        public void Execute(UpdaterData data)
        {
            var document = data.Document;
            var addIds = data.GetAddedElementIds();
            foreach(var aId in addIds)
            {
                var element = document.GetElement(aId);
                var familyInstance = element as FamilyInstance;
                if(familyInstance != null && familyInstance.Family.Name.Equals("CustomWall"))
                {
                    //注意此处不需要开启Transaction事务。
                    var family = familyInstance.Family;
                    var redWallType = family.GetInstanceTypes().FirstOrDefault(x => x.Name.Equals("红色墙"));
                    var ids = ElementTransformUtils.CopyElements(document, new List<ElementId>() { aId }, new Vector3d(0, 1000, 0));
                    var copyInstance = document.GetElement(ids.FirstOrDefault()) as FamilyInstance;
                    copyInstance.ChangeInstanceType(redWallType.Id);
                    break;
                }
            }
        }

        public UpdaterId GetUpdaterId()
        {
            return m_id;
        }

        public string GetUpdaterName()
        {
            return "GDMP Custom Updater";
        }
    }

    /// <summary>
    /// 实现更新过滤器，对指定图元使用关联更新。
    /// </summary>
    public class UpdaterFilter : IUpdaterFilter
    {
        public bool PassesFilter(Element element)
        {
            var familyInstance = element as FamilyInstance;
            if (null != familyInstance && 
                familyInstance.InstanceType.Name.Equals("灰色墙"))
            {
                return true;
            }
            return false;
        }

        public bool PassesFilterForId(Document document, ElementId id)
        {
            return true;
        }
    }
}
